GLOBAL  register_task
GLOBAL  context_switch
GLOBAL  exit_switch
GLOBAL start_init_asm

EXTERN pageDown
EXTERN pageUp
EXTERN	printf
EXTERN debug

SECTION .text


start_init_asm:
	push ebp		; Generar el stack frame
	mov ebp, esp

	; Obtener parametros
	mov eax, [ebp + 0x0c]	; ax = sp que se debe cargar
	mov edx, [ebp + 0x08]	; edx = eip que se debe cargar

	mov esp, eax		; Cargar el nuevo sp (proceso hijo)
	jmp edx			; ejecutar init
	ret			; esto nunca se ejecuta


; Subrutina: register_task
; ------------------------
; Recibe como primer parametro la direccion de la funcion que se desea ejecutar,
; como segundo el sp que se pretende cargar y como tercero la direccion de
; memoria donde se debe guardar el sp. Obviamente, tambien resguarda el
; contexto del proceso en ejecucion.

register_task:
	push ebp		; Generar el stack frame
	mov ebp, esp

	pushad			; Salvar EAX, ECX, EDX, EBX, ESP, EBP, ESI, EDI
	pushfd			; Salvar los flags

	; Cuando se vuelva a ejecutar el proceso padre, Se debera levantar
	; cargar el sp y el eip aqui guardados para que dicho proceso finalice
	; la ejecucion de esta subrutina

	; Obtener parametros
	mov eax, [ebp + 0x0c]	; ax = sp que se debe cargar
	mov edx, [ebp + 0x08]	; edx = eip que se debe cargar
	mov ebx, [ebp + 0x10]	; ebx = argc
	mov ecx, [ebp + 0x14]	; ecx = argv

	; ---- Cargamos el stack del nuevo proceso ----
	mov edi, esp		; salvar el sp del proceso inicial
	mov esp, [eax]		; Cargar el nuevo sp (proceso hijo)
	push ecx		; pushear argv
	push ebx		; pushear argc
	push 0			; pushear la direccion de retorno que nunca s
				; utilizara ya que los procesos terminan con
				; exit_task pero el compilador de c busca los
				; argumentos a partir de ebp + 0x08.
	push edx		; pushear la dir. de retorno
				; (la primera instruccion del prog)
	push ebp		; Crear un stack frame igual al que genera
				; context_switch
	mov ebp, esp		; Cuando salva el estado del proceso actual.
	pushad
	pushfd

	mov [eax], esp		; Guardar sp del proceso
	mov esp, edi		; volver al stack del proceso inicial
	; ---- Volvemos a nuestro stack ----

	popfd			; restaurar los flags y los registros
	popad

	mov esp, ebp		; desarmar el stack frame
	pop ebp
	ret

; Subrutina: context_switch
; -------------------------
; Esta subrutina se encarga de intercambiar los contextos de 2 tareas.
; Para ello debe recibir como parametro el sp de la tarea a la que se quiere
; switchear y la direccion de memoria donde se debe guardar el sp actual

context_switch:
	push ebp		; Generar el stack frame
	mov ebp, esp

	;call debug
	pushad			; Salvar EAX, ECX, EDX, EBX, ESP, EBP, ESI, EDI
	pushfd			; Salvar los flags

	; Cuando se vuelva a ejecutar el proceso padre, Se debera levantar
	; cargar el sp y el eip aqui guardados para que dicho proceso finalice
	; la ejecucion de esta subrutina

	mov eax, [ebp + 8]	; ax = sp que se debe cargar
	mov ecx, [ebp + 12]	; ecx = direccion donde se debe guardar sp
	;call debug
	mov [ecx], esp		; Guardar sp
	mov esp, eax		; Cargar el sp

; Cuando se empiece a ejecutar este codigo, el sp del nuevo proceso ya debe estar cargado
	popfd			; Restaurar los flags
	popad			; Restaurar los registros
	mov esp, ebp		; Eliminar el stack frame
	pop ebp
	sti
	ret

exit_switch:
	push ebp		; Generar el stack frame
	mov ebp, esp

	;No pusheo los parametros porque se esta saliendo de la funcion y nunca se
	; vuelve
	;pushad			; Salvar EAX, ECX, EDX, EBX, ESP, EBP, ESI, EDI
	;pushfd			; Salvar los flags

	; Cuando se vuelva a ejecutar el proceso padre, Se debera levantar
	; cargar el sp y el eip aqui guardados para que dicho proceso finalice
	; la ejecucion de esta subrutina

	mov eax, [ebp + 0x08]	; ax = sp que se debe cargar
	mov ebx, [ebp + 12]
	push eax
	push ebx
	call pageDown
	pop ebx
	pop eax
	mov esp, eax		; Cargar el sp

; Cuando se empiece a ejecutar este codigo, el sp del nuevo proceso ya debe estar cargado
	popfd			; Restaurar los flags
	popad			; Restaurar los registros
	mov esp, ebp		; Eliminar el stack frame
	pop ebp
	sti
	ret
	